//
// CrackJarFile
//
// Copyright (C) jextra.net.
//
//  This file is part of the Crack build system.
//
//  The Crack build system is free software; you can redistribute it 
//  and/or modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  The Crack build system is distributed in the hope that it will be 
//  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with the Crack build system; if not, write to the Free
//  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
//  02111-1307 USA.
//

package net.jextra.crack.tool;

import java.io.*;
import java.util.jar.*;
import java.util.zip.*;
import net.jextra.crack.type.*;

/**
 * <p>
 * JAR file manipulation.
 * </p>
 */
public class CrackJarFile
{
    // ============================================================
    // Fields
    // ============================================================

    private JarOutputStream out;

    // ============================================================
    // Constructors
    // ============================================================

    public CrackJarFile( String filename )
        throws IOException
    {
        this( new File( filename ) );
    }

    public CrackJarFile( String filename, Manifest man )
        throws IOException
    {
        this( new File( filename ), man );
    }

    public CrackJarFile( File file )
        throws IOException
    {
        this( new FileOutputStream( file ) );
    }

    public CrackJarFile( File file, Manifest man )
        throws IOException
    {
        this( new FileOutputStream( file ), man );
    }

    public CrackJarFile( OutputStream outStream )
        throws IOException
    {
        Manifest man = new Manifest();
        man.getMainAttributes().put( Attributes.Name.MANIFEST_VERSION, "1.0" );
        out = new JarOutputStream( outStream, man );
    }

    public CrackJarFile( OutputStream outStream, Manifest man )
        throws IOException
    {
        out = new JarOutputStream( outStream, man );
    }

    // ============================================================
    // Methods
    // ============================================================

    // ----------
    // public
    // ----------

    public void addFiles( StrainedFileSet fileSet )
        throws IOException
    {
        for ( File file : fileSet.getFiles() )
        {
            addFile( fileSet.getRootDir(), file );
        }
    }

    public void addZipFile( File zipFile )
        throws IOException
    {
        addZipFile( zipFile, true );
    }


    public void addZipFile( File zipFile, boolean includeMetaInf )
        throws IOException
    {
        byte[] buf = new byte[5000];

        ZipInputStream zipIn = new ZipInputStream( new FileInputStream( zipFile ) );
        ZipEntry entry = null;
        while ( ( entry = zipIn.getNextEntry() ) != null )
        {
            if ( entry.isDirectory() )
            {
                continue;
            }
            // Ignore MANIFEST files in zips.
            else if ( entry.getName().endsWith( "/MANIFEST.MF" ) )
            {
                continue;
            }
            // Ignore META-INF data in zip files.
            else if ( !includeMetaInf && entry.getName().toLowerCase().startsWith( "meta-inf" ) )
            {
                continue;
            }

            try
            {
                out.putNextEntry( entry );
            }
            catch ( ZipException ex )
            {
                // Ignore duplicates.
                continue;
            }

            int len;
            while ( ( len = zipIn.read( buf ) ) > 0 )
            {
                out.write( buf, 0, len );
            }
        }
        zipIn.close();
    }

    public void addFile( File relativeDir, File file )
        throws IOException
    {
        byte[] buf = new byte[5000];

        int rootLen = relativeDir.getCanonicalPath().length();

        FileInputStream in = new FileInputStream( file );
        // Warning! the replacement of \ to / is required.
        out.putNextEntry( new ZipEntry( file.getCanonicalPath().substring( rootLen +
            1 ).replace( '\\', '/' ) ) );

        int len;
        while ( ( len = in.read( buf ) ) >= 0 )
        {
            out.write( buf, 0, len );
        }

        in.close();
        out.closeEntry();
    }

    public void close()
        throws IOException
    {
        out.close();
    }
}

